#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include <time.h>

#include "hqjgdata.h"
#include "ringBuffer.h"
#include "utils.h"
#include "aexgpio.h"
#include "kc031service.h"


#include "head.h"

#ifdef USE_HQJG_UDP

static u8 en_input_ctrl = 0;	//使能了输入控制

void hqjd_handle_uevent(unsigned int oldPin, unsigned int newPin)
{
	u8 cnt_pin = 0;
	u32 mask_in = AEXIN_MASK();
	u32 templ = 0;
	u32 edge_up_pin = 0;

	//psus_log(10, "oldPin->newPin:%04x->%04x", oldPin, newPin);
	for ( cnt_pin = 0; cnt_pin < NUM_AEXGPIO_IN; cnt_pin++)
	{
		templ = 1 << cnt_pin;
		if( templ & mask_in == 0 )
			continue;
		if( ( templ & newPin) && !( templ & oldPin) ) //得到上升沿
		{
			edge_up_pin |= templ;
		}
	}
	if( en_input_ctrl )
	{
		for ( cnt_pin = 0; cnt_pin < NUM_AEXGPIO_IN; cnt_pin++)
		{
			templ = 1 << cnt_pin;
			if( (edge_up_pin & templ) && get_psus_data()->hcsdata.hasgpio ){
				aexgpio_set_out_by_index(cnt_pin, 1 );
			}
		}
	}
	
	hqjg_report_iostatus(0x1E, aexgpio_get_in() & 0xff);
}

void thread_delay_onoff(void* arg)
{
	delay_onOff_data *operation = NULL;
	u32 level_set;

	operation = arg;
	level_set = operation->operate == CMD_HQJD_MUL_ON_DELAY ? 1 : 0;

	// SYS_PRINT("-----thread--flag_pins--%04x-\n", operation->flag_pins);
	// SYS_PRINT("-----thread--opera--%02x-\n", operation->operate);
	for (u8 cnt_pin = 0; cnt_pin < NUM_AEXGPIO_OUT; ++cnt_pin)
	{
		usleep(600 * 1000);		//延时600ms
		if ( BIT_READ( operation->flag_pins,_BIT(cnt_pin) ) )
		{
			//SYS_PRINT("-----thread--pin--%d----\n",AEXOUT_MIN_INDEX + cnt_pin);
			if(get_psus_data()->hcsdata.hasgpio){
				aexgpio_set_out_by_index(cnt_pin, level_set );
			}
		}
	}
	free(arg);
	pthread_exit(NULL);
}

/*
Z在计划任务中进行补充/更新
*/
void hqjd_plan_set_crontabFile(u8 ch, u8 isOff, u8* buf_src)
{
	// 计划任务的描述文件
	char file_crontab[] = "/etc/crontab/root";
	FILE *fp;
	char buf_read[512];
	char buf_write[512];
	char* read_ret;
	char arg_ret[7][MAX_ARG_LEN];
	u8 flag_plan_en, flag_plan_dis;
	fpos_t position;

	memset(buf_write, 0, sizeof(buf_write));
	// 如果文件不存在
	fp = fopen(file_crontab, "r+");
	if (fp == NULL) {
		psus_error("%s: file %s open error\n", __FUNCTION__, file_crontab);
		return;
	}
	char* buff_data = HQJG_CMD_GET_DATA(buf_src);
	//找出传进来的buff种有哪些天是需要计划任务的
	for (u8 cnt_week = 0; cnt_week < 7; cnt_week++)
	{
		if( ( *(buff_data + cnt_week * 2) < 24 ) && ( *(buff_data + cnt_week * 2 + 1) < 60 ) )
		{
			BIT_SET(flag_plan_en, cnt_week);	// 需要添加的工作计划
		}
		else
		{
			BIT_SET(flag_plan_dis, cnt_week);	//需要删除的工作计划
		}
	}

	//psus_log(10,"ch:%d, en plan flags:%02x, dis plan flags:%02x",ch,flag_plan_en, flag_plan_dis);
	do
	{
		memset(buf_read, 0, sizeof(buf_read));
		read_ret = fgets(buf_read, sizeof(buf_read), fp);
		split_arguments(buf_read, arg_ret, 7, ' ');
		
		//找到控制输出的命令
		if( strstr(arg_ret[6], "--cmd:") )	
		{
			u8 read_ch =  arg_ret[6][9] - '0';	//找到当前crontab控制的通道
			u8 read_isOff = arg_ret[6][11] - 'D';//判断是开还是关
			u8 read_iweek = arg_ret[4][2] - '0';// 判断是周几的计划任务

			if( read_ch == ch && read_isOff == isOff )//任务表中找到了计划任务
			{
				if( BIT_READ(flag_plan_en, read_iweek) )
				{
					BIT_CLEAR(flag_plan_en, read_iweek);
					fsetpos(fp, &position);
					fputs("\n", fp);
					sprintf(buf_write, "*/%d */%d * * */%01d /bin/kc031srv --cmd:AA0%c0%d00000000000000000000000000000000BB",
					*(buff_data + read_iweek * 2 + 1), *(buff_data + read_iweek * 2), read_iweek, isOff ? 'E':'D', ch);
					fputs(buf_write, fp);					
				}
				else if( BIT_READ(flag_plan_dis, read_iweek) )
				{
					BIT_CLEAR(flag_plan_dis, read_iweek);
					fsetpos(fp, &position);
					fputs("\n", fp);
					fputs("\n", fp);		
				}
			}
		}else{
			fgetpos(fp,&position);               //获得当前的偏移量
		}
	} while ( read_ret);

	if( flag_plan_en )//任务表中未找到计划任务
	{
		for (u8 cnt_week = 0; cnt_week < 7; cnt_week++)
		{
			if ( BIT_READ(flag_plan_en , cnt_week) )
			{
				fputs("\n", fp);
				sprintf(buf_write, "*/%d */%d * * */%01d /bin/kc031srv --cmd:AA0%c0%d00000000000000000000000000000000BB",
					*(buff_data + cnt_week * 2 + 1), *(buff_data + cnt_week * 2), cnt_week, isOff ? 'E':'D', ch);
				fputs(buf_write, fp);	
			}
		}
	}
	fclose(fp);
}

/*
定时开关，数据解析
*/
void hqjd_set_plan_table(u8 cmd, u8* buf_src)
{
	u8 is_setOff = 0;

	switch (cmd)	//判断是计划开，还是计划关
	{
	case CMD_HQJD_PLAN_ON:
		is_setOff = 0;
		break;
	case CMD_HQJD_PLAN_OFF:
		is_setOff = 1;
		break;
	default:
		psus_error("hqjd_set_plan_table : unknow cmd(%02x)!", cmd);
		return;
	}

	switch (HQJG_CMD_GET_BTN(buf_src))
	{
	case 0:
	case 1:
	case 2:
	case 3:
	case 4:
	case 5:
	case 6:
	case 7:
		hqjd_plan_set_crontabFile(HQJG_CMD_GET_BTN(buf_src), is_setOff, buf_src);
		break;
	case 0xff:
		hqjd_plan_set_crontabFile(0, is_setOff, buf_src);
		hqjd_plan_set_crontabFile(1, is_setOff, buf_src);
		hqjd_plan_set_crontabFile(2, is_setOff, buf_src);
		hqjd_plan_set_crontabFile(3, is_setOff, buf_src);
		hqjd_plan_set_crontabFile(4, is_setOff, buf_src);
		hqjd_plan_set_crontabFile(5, is_setOff, buf_src);
		hqjd_plan_set_crontabFile(6, is_setOff, buf_src);
		hqjd_plan_set_crontabFile(7, is_setOff, buf_src);
		break;
	default:
		psus_error("hqjd_set_plan_table : unknow channel (%d)!", HQJG_CMD_GET_BTN(buf_src));
		return;
	}
}

/*
GPIO混合设置模式，需要进行过滤解析
过滤出需要开/需要关的bits，然后再根据功能码操作gpio

*/
void hqjd_set_multiply_gpio(u8 cmd, u8* buf_src)
{
	u32 flag_on,flag_off,templ,templ_data;
	pthread_t thread_delay_aexgpio;
	delay_onOff_data *operation = NULL;

	//网上看到的做法，如果operation被定义为结构体，取值传参会出错
 	operation = ( delay_onOff_data *)malloc(sizeof(delay_onOff_data)); 

	flag_on = 0;
	flag_off = 0;
	
	for ( templ = 0; templ < NUM_AEXGPIO_OUT; ++templ )
	{
		templ_data = *(HQJG_CMD_GET_DATA(buf_src) + templ);
		//SYS_PRINT("hqjd pin--val===%02x--%02x:\n",templ,templ_data);
		if( templ_data  == 0x01 )
		{
			BIT_SET(flag_on, _BIT(templ));
		}else if( templ_data == 0x02 )
		{
			BIT_SET(flag_off, _BIT(templ));
		}
	}
	//SYS_PRINT("hqjd mul gpios flag_on: %04x\n",flag_on);
	//SYS_PRINT("hqjd mul gpios flag_off: %04x\n",flag_off);
	///以下操作待根据硬件确定
	switch ( cmd )
	{
	case CMD_HQJD_MUL_ON_NOW:	
		if(get_psus_data()->hcsdata.hasgpio){
			aexgpio_set_out(flag_on,flag_on);
		}
		break;
	case CMD_HQJD_MUL_OFF_NOW:
		if(get_psus_data()->hcsdata.hasgpio){
			aexgpio_set_out(flag_off,0);
		}
		break;
	case CMD_HQJD_MUL_ON_DELAY:	
		operation->flag_pins = flag_on;
		operation->operate = cmd;
		pthread_create(&thread_delay_aexgpio,NULL,(void*)&thread_delay_onoff,(void*)operation);	//换成timer
		break;
	case CMD_HQJD_MUL_OFF_DELAY:
		operation->flag_pins = flag_off;
		operation->operate = cmd;
		pthread_create(&thread_delay_aexgpio,NULL,(void*)&thread_delay_onoff,(void*)operation);
		break;
	default:
		psus_error("hqjd multiply gpio : unknow cmd(%02x)!",cmd);
		break;
	}	
}

void hqjd_report_plan(u8 cmd, u8 * buff_src)
{
	char  buf[30];
	int index;
	unsigned value = 0;
	psus_config *pusdata = get_psus_data();

	if(get_psus_data()->hcsdata.hasgpio){
		value =  aexgpio_get_out();
	}
	memset(buf,0,sizeof(buf));
	HQJG_SET_BEGIN(buf);
	HQJG_SET_CMD(buf,cmd);
	HQJG_SET_BTN(buf, HQJG_GET_BTN(buff_src));
	memcpy(HQJG_GET_DATA(buf), HQJG_GET_DATA(buff_src),HQJD_TIME_NUM);
	HQJG_SET_CRC(buf);
	HQJG_SET_END(buf);
	if(pusdata->hcsdata.last_cmd_from == AEX_LCF_UDP || pusdata->hcsdata.last_cmd_from ==AEX_LCF_ME){
		SendtoServer(buf,HQJG_GET_PACKET_LEN(buf));
	}
	if(pusdata->hcsdata.bsuart.passto == AEX_UART_PACKNET && pusdata->hcsdata.tcp_fd != INVAILDSOCKET && 
		(pusdata->hcsdata.hasgpio == AEX_LCF_TCP || pusdata->hcsdata.last_cmd_from == AEX_LCF_ME)){
		write(pusdata->hcsdata.tcp_fd,buf,HQJG_GET_PACKET_LEN(buf));
	}

}

/*
btn :应该是板子上的输入口状态
*/
void hqjg_report_iostatus(unsigned char cmd,unsigned char btn)
{
	char  buf[30];
	int index;
	unsigned int value = 0;
	psus_config *pusdata = get_psus_data();

	if(get_psus_data()->hcsdata.hasgpio){
		value =  aexgpio_get_out();
	}
	//psus_log(10, "---out value:%04x---", value);
	memset(buf,0,sizeof(buf));
	HQJG_SET_BEGIN(buf);
	HQJG_SET_CMD(buf,cmd);
	HQJG_SET_BTN(buf,btn);
	//下面读取每个输出口状态
	for(index = 0; index < NUM_AEXGPIO_OUT; index++){

		buf[index+3] = (value&(1<<index))==0?2:1;	//还未确定，高位在前还是低位在前？
	}
	HQJG_SET_CRC(buf);
	HQJG_SET_END(buf);
	SendRspSocket(pusdata,buf,HQJG_GET_PACKET_LEN(buf));
	// if(pusdata->last_cmd_from == AEX_LCF_UDP || pusdata->last_cmd_from ==AEX_LCF_ME){
	// 	SendUdpSocket(pusdata,buf,HQJG_GET_PACKET_LEN(buf));
	// }
	// if(pusdata->uartpassto == AEX_UART_PACKNET && pusdata->tcp_fd != INVAILDSOCKET && 
	// 	(pusdata->last_cmd_from == AEX_LCF_TCP || pusdata->last_cmd_from == AEX_LCF_ME)){
	// 	psus_hint("Send tcp to %s:%d len=%d",IP2Str(pusdata->tcp_addr.sin_addr.s_addr),ntohs(pusdata->tcp_addr.sin_port),HQJG_GET_PACKET_LEN(buf));
	// 	write(pusdata->tcp_fd,buf,HQJG_GET_PACKET_LEN(buf));
	// }
}

void hqjg_heart(int fd,char *buf,char *data,size_t len)
{
	hqjg_report_iostatus(0x1E,0xFF);
}

void GetSystemTime(char* out)
{
	struct timeval t;
	time_t b_time;
	struct tm *tim;

	b_time = time(NULL);
	tim = localtime(&b_time);

    gettimeofday(&t, NULL);

	/*
	注意：
	KC030协议定义【年】格式为0x1411,代表2017年
	*/

	//2017年为0x07e1
	// out[0] = ((tim->tm_year + 1900)&0xFF00)>>8;
	// out[1] = ((tim->tm_year + 1900)&0x00FF);

	out[0] = (tim->tm_year + 1900) / 100;
	out[1] = (tim->tm_year + 1900) % 100;
	out[2] = tim->tm_mon + 1;
	out[3] = tim->tm_mday;
	out[4] = tim->tm_hour;
	out[5] = tim->tm_min;
	out[6] = tim->tm_sec;
}

void SetSysTime(char *dt)
{
	struct tm tim = {
        //.tm_year = (dt[0]<<8|dt[1]) - 1900, 
		.tm_year = ( dt[0] * 100 + dt[1] ) - 1900,
        .tm_mon = dt[2] - 1, 
        .tm_mday = dt[3],
        .tm_hour = dt[4], 
        .tm_min = dt[5], 
        .tm_sec = dt[6], 
    };

	struct timeval tv_set;

	memset(&tv_set, 0, sizeof(tv_set) );
	tv_set.tv_sec  = mktime(&tim );
	tv_set.tv_usec = 0;
	if (settimeofday(&tv_set,NULL)<0) {
		perror("settimeofday");
	}
}

void hqjg_report_datetime(unsigned char cmd)
{
	char  buf[30];
	u8 time_now[7];
	int index;
	unsigned value =  aexgpio_get_out();
	psus_config *pusdata = get_psus_data();

	memset(time_now,0,sizeof(time_now));
	memset(buf,0,sizeof(buf));

	GetSystemTime(time_now);	
	HQJG_SET_BEGIN(buf);
	HQJG_SET_CMD(buf,cmd);
	HQJG_SET_BTN(buf,0x00);
	//SetSysTime(HQJG_CMD_GET_DATA(buf));
	memcpy(HQJG_CMD_GET_DATA(buf), time_now,sizeof(time_now) );
	HQJG_SET_CRC(buf);
	HQJG_SET_END(buf);
	SendRspSocket(pusdata,buf,HQJG_GET_PACKET_LEN(buf));
	// if(pusdata->last_cmd_from == AEX_LCF_UDP || pusdata->last_cmd_from ==AEX_LCF_ME){
	// 	SendUdpSocket(pusdata,buf,HQJG_GET_PACKET_LEN(buf));
	// }
	// if(pusdata->uartpassto == AEX_UART_PACKNET && pusdata->tcp_fd != INVAILDSOCKET && 
	// 	(pusdata->last_cmd_from == AEX_LCF_TCP || pusdata->last_cmd_from ==AEX_LCF_ME)){
	// 	write(pusdata->tcp_fd,buf,HQJG_GET_PACKET_LEN(buf));
	// }
}

void hqjg_cmd(unsigned char *buf,size_t len)
{
	unsigned char *p = buf;

	if(HQJG_CMD_GET_END(p) == HQJG_CMD_END){ //&& HQJG_CMD_GET_CRC(p) == crc8(HQJG_CMD_GET_DATA(p),HQJG_CMD_GET_LEN(p))){
		//找到了包尾及CRC校验成功，开始解析使用命令	
		// SYS_PRINT("\n==hqjd=cmd-%02x--%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x--%02x==\n",
		// 			*(p+1),*(p+2),*(p+3),*(p+4),*(p+5),*(p+6),*(p+7),*(p+8),*(p+9),*(p+10),
		// 			*(p+11),*(p+12),*(p+13),*(p+14),*(p+15),*(p+16),*(p+17),*(p+18));
		switch (HQJG_CMD_GET_CMD(p))
		{
		case CMD_HQJD_ALLON:
			aexgpio_set_out(0xFF,0xFF);
			//hqjg_report_iostatus(0x0A,0xFF);
			hqjg_report_iostatus(CMD_HQJD_ALLON,aexgpio_get_in() & 0xff);
			break;
		case CMD_HQJD_ALLOFF:
			if(get_psus_data()->hcsdata.hasgpio){
				aexgpio_set_out(0xFF,0x00);
			}
			//hqjg_report_iostatus(0x0B,0xFF);
			hqjg_report_iostatus(CMD_HQJD_ALLOFF,aexgpio_get_in() & 0xff);
			break;		
		case CMD_HQJD_GET_STA:
			hqjg_report_iostatus(CMD_HQJD_GET_STA,aexgpio_get_in() & 0xff);
			break;	
		case CMD_HQJD_SET_TIME:
			SetSysTime(HQJG_CMD_GET_DATA(buf));
			hqjg_report_datetime(CMD_HQJD_SET_TIME);
			break;
		case CMD_HQJD_GET_TIME:
			hqjg_report_datetime(CMD_HQJD_GET_TIME);
			break;
		case CMD_HQJD_SINGLE_ON:
			if(get_psus_data()->hcsdata.hasgpio){
				aexgpio_set_out_by_index(HQJG_CMD_GET_BTN(buf) ,1);
			}
			hqjg_report_iostatus(CMD_HQJD_SINGLE_ON,HQJG_CMD_GET_BTN(buf));
			break;
		case CMD_HQJD_SINGLE_OFF:
			if(get_psus_data()->hcsdata.hasgpio){
				aexgpio_set_out_by_index(HQJG_CMD_GET_BTN(buf) ,0);
			}
			hqjg_report_iostatus(CMD_HQJD_SINGLE_OFF,HQJG_CMD_GET_BTN(buf));
			break;
		case CMD_HQJD_REQ_STA:		//查询状态
			//hqjg_report_iostatus(0x2B,0xFF);
			hqjg_report_iostatus(CMD_HQJD_REQ_STA,aexgpio_get_in() & 0xff);
			break;
		case CMD_HQJD_INPUT_CTRL_EN:		//IO控制开,IO按键输入控制功能,*此指令需有掉电保存功能。*
			hqjg_report_iostatus(CMD_HQJD_INPUT_CTRL_EN,aexgpio_get_in() & 0xff);
			break;
		case CMD_HQJD_INPUT_CTRL_DIS:		//IO控制关,IO按键输入控制功能,*此指令需有掉电保存功能。*
			hqjg_report_iostatus(CMD_HQJD_INPUT_CTRL_DIS,aexgpio_get_in() & 0xff);
			break;
		case CMD_HQJD_MUL_ON_NOW:
			hqjd_set_multiply_gpio(CMD_HQJD_MUL_ON_NOW,p);
			hqjg_report_iostatus(CMD_HQJD_MUL_ON_NOW,aexgpio_get_in() & 0xff);
			break;
		case CMD_HQJD_MUL_OFF_NOW:		//设置按钮即时关
			hqjd_set_multiply_gpio(CMD_HQJD_MUL_OFF_NOW,p);
			hqjg_report_iostatus(CMD_HQJD_MUL_OFF_NOW,aexgpio_get_in() & 0xff);
			break;
		case CMD_HQJD_MUL_ON_DELAY:		//设置按钮延时开，每个IO的设置间隔600ms
			hqjd_set_multiply_gpio(CMD_HQJD_MUL_ON_DELAY,p);
			hqjg_report_iostatus(CMD_HQJD_MUL_ON_DELAY,aexgpio_get_in() & 0xff);
			break;
		case CMD_HQJD_MUL_OFF_DELAY:		//设置按钮延时关，每个IO的设置间隔600ms
			hqjd_set_multiply_gpio(CMD_HQJD_MUL_OFF_DELAY,p);
			hqjg_report_iostatus(CMD_HQJD_MUL_OFF_DELAY,aexgpio_get_in() & 0xff);
			break;
		case CMD_HQJD_PLAN_ON:		//设置工作日定时开,*此指令需有掉电保存功能，一天中每一线路只分别有一次定时开关。*
			hqjd_set_plan_table(CMD_HQJD_PLAN_ON,p);
			hqjd_report_plan(CMD_HQJD_PLAN_ON, p);
			break;
		case CMD_HQJD_PLAN_OFF:		//设置工作日定时关,*此指令需有掉电保存功能，一天中每一线路只分别有一次定时开关。*
			hqjd_set_plan_table(CMD_HQJD_PLAN_OFF,p);
			hqjd_report_plan(CMD_HQJD_PLAN_OFF, p);
			break;
		case CMD_HQJD_AUTO_HEART:
			hqjg_report_iostatus(CMD_HQJD_AUTO_HEART,0xFF);
			break;
		default:
			break;
		}
	}
}

#endif //USE_HQJG_UDP
 